package wsPool

import (
	"errors"
	"fmt"
	"gitee.com/rczweb/wsPool/util/grpool"
	"net/http"
	"sync"
	"time"
)

/*
第一步，实例化连接对像
*/
func NewClient(conf *Config) *Client {
	if conf.Goroutine < 5 {
		conf.Goroutine = 20
	}
	var client *Client
	oldclient := wsSever.hub.oldClients.Remove(conf.Id)
	if oldclient != nil {
		c := oldclient.(*Client)
		client = c
		client.grpool.Close()
	} else {
		client = &Client{
			Id:     conf.Id,
			types:  conf.Type,
			hub:    wsSever.hub,
			sendCh: make(chan *Message, Max_recvCh_len),
			recvCh: make(chan *Message, Max_sendCh_len),
			mux:    new(sync.Mutex),
		}
	}
	client.recvPing = make(chan int)
	client.sendPing = make(chan int)
	client.channel = conf.Channel
	client.grpool = grpool.NewPool(conf.Goroutine)
	client.IsClose = make(chan bool)
	client.OnError(nil)
	client.OnOpen(nil)
	client.OnMessage(nil)
	client.OnClose(nil)
	client.OnPing(nil)
	client.OnPong(nil)
	return client
}

//开启连接
// serveWs handles websocket requests from the peer.
func (c *Client) OpenClient(w http.ResponseWriter, r *http.Request, head http.Header) {
	defer dump()
	conn, err := upgrader.Upgrade(w, r, head)
	if err != nil {
		if c.onError != nil {
			c.onError(err)
		}
		return
	}
	r.Close = true
	c.conn = conn
	c.conn.SetReadLimit(maxMessageSize)
	c.conn.SetReadDeadline(time.Now().Add(pongWait))
	c.pingPeriodTicker = time.NewTimer(pingPeriod)
	c.conn.SetPongHandler(func(str string) error {
		c.conn.SetReadDeadline(time.Now().Add(pongWait))
		fmt.Println("收到pong---", c.Id, str)
		c.pingPeriodTicker.Reset(pingPeriod)
		c.onPong()
		return nil
	})

	c.conn.SetPingHandler(func(str string) error {
		c.conn.SetReadDeadline(time.Now().Add(pongWait))
		c.pingPeriodTicker.Reset(pingPeriod)
		fmt.Println("收到ping---", c.Id, str)
		c.recvPing <- 1
		/*if err := c.conn.WriteMessage(websocket.PongMessage, nil); err != nil {
			c.onError(errors.New("回复客户端PongMessage出现异常:"+err.Error()))
		}*/
		c.onPing()
		return nil
	})
	/*c.conn.SetCloseHandler(func(code int, str string) error {
		//收到客户端连接关闭时的回调
		glog.Error("连接ID："+c.Id,"SetCloseHandler接收到连接关闭状态:",code,"关闭信息：",str)
		return nil
	})*/

	// Allow collection of memory referenced by the caller by doing all work in
	// new goroutines.
	//连接开启后瑞添加连接池中
	c.openTime = time.Now()
	c.hub.AddClient(c)
/*	go c.writePump()
	go c.readPump()*/
	c.grpool.Add(c.writePump)
	c.grpool.Add(c.readPump)
	//开始接收消息
	c.grpool.Add(c.recvMessage)
	c.onOpen()

}

/*
获取连接对像运行过程中的信息
*/
func (c *Client) GetRuntimeInfo() *RuntimeInfo {
	return &RuntimeInfo{
		Id:              c.Id,
		Type:            c.types,
		Channel:         c.channel,
		OpenTime:        c.openTime,
		LastReceiveTime: c.lastSendTime,
		LastSendTime:    c.lastSendTime,
		Ip:              c.conn.RemoteAddr().String(),
	}
}

/*回调添加方法*/

/*监听连接对象的连接open成功的事件*/
func (c *Client) OnOpen(h func()) {
	if h == nil {
		c.onOpen = func() {

		}
		return
	}
	c.onOpen = h
}

func (c *Client) OnPing(h func()) {
	if h == nil {
		c.onPing = func() {

		}
		return
	}
	c.onPing = h
}

func (c *Client) OnPong(h func()) {
	if h == nil {
		c.onPong = func() {

		}
		return
	}
	c.onPong = h
}

/*监听连接对象的连接open成功的事件*/
func (c *Client) OnMessage(h func(msg ...*Message)) {
	if h == nil {
		c.onMessage = func(msg ...*Message) {

		}
		return
	}
	c.onMessage = h
}


/*监听连接对象的连接open成功的事件*/
func (c *Client) OnClose(h func()) {
	if h == nil {
		c.onClose = func() {

		}
		return
	}
	c.onClose = h
}

/*监听连接对象的错误信息*/
func (c *Client) OnError(h func(err error)) {
	if h == nil {
		c.onError = func(err error) {
		}
		return
	}
	c.onError = h
}

// 单个连接发送消息(消息可以是一个，也可以是多个 )
func (c *Client) Send(msg ...*Message) error {
	if len(msg)==0 {

	}
	select {
	case <-c.IsClose:
		return errors.New("连接ID：" + c.Id + "ws连接己经断开，无法发送消息")
	default:
		for i:=0;i<len(msg);i++ {
			c.send(msg[i])
		}
	}
	return nil
}

//服务主动关闭连接
func (c *Client) Close() {
	c.close()
}

/*
包级的公开方法
所有包级的发送如果连接断开，消息会丢失
*/

//通过连接池广播消息，每次广播只能指定一个类型下的一个频道

/*
广播消息方法
messageType=1 为string
messageType=2 为[]byte
msg 为消息内容按指定的类型输入
channel 为指定频道进行广播可为空，也可以多个
	如果没有指定channel 是广播所有连接
	注意，channel不能为0
*/

func Broadcast(msg *Message, channel ...string) error {
	if msg == nil {
		return errors.New("广播发送的消息内容不能为空！")
	}

	if len(channel) == 0 {
		return wsSever.hub.Broadcast("", msg)
	} else {
		for _, o := range channel {
			wsSever.hub.Broadcast(o, msg)
		}
	}
	return nil
}

/*
通过id获取相应的连接对象
*/
func GetClientById(id string) *Client {
	c := wsSever.hub.clients.Get(id)
	if c != nil {
		return c.(*Client)
	}
	return nil
}
